
#[derive(Debug, PartialEq)]
pub enum Instance {
    R(Resistance),
    C(Capacitance),
    L(Inductance),
    V(Voltage),
    I(Current),
}

#[derive(Debug, PartialEq)]
pub struct Resistance {
    pub name: String,
    pub node1: String,
    pub node2: String,
    pub value: f64,
}

#[derive(Debug, PartialEq)]
pub struct Capacitance {
    pub name: String,
    pub node1: String,
    pub node2: String,
    pub value: f64,
}

#[derive(Debug, PartialEq)]
pub struct Inductance {
    pub name: String,
    pub node1: String,
    pub node2: String,
    pub value: f64,
}

#[derive(Debug, PartialEq)]
pub struct Voltage {
    pub name: String,
    pub node1: String,
    pub node2: String,
    pub kind: VoltageKind,
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum VoltageKind {
    DC(DCVoltageKind),
    Sin(SinVoltageKind),
    Pulse(PulseVoltageKind),
}

impl VoltageKind {
    pub fn voltage(&self, time: f64) -> f64 {
        match self {
            VoltageKind::DC(dc) => { dc.value }
            VoltageKind::Sin(sin) => {
                sin.amplitude * (2. * std::f64::consts::PI * sin.frequence * time).sin()
            }
            VoltageKind::Pulse(pulse) => {
                if time < pulse.delay {
                    pulse.low_voltage
                } else {
                    let time = time - pulse.delay;
                    let ratio = time / pulse.period;
                    let fractional = ratio.fract();

                    /*
                        --------+--------------+--------+--------------
                          rise    high_voltage    fall     low_voltage
                    */

                    let rise = pulse.rise_time / pulse.period;
                    let high_voltage = pulse.pulse_width / pulse.period;
                    let fall = (pulse.pulse_width + pulse.fall_time) / pulse.period;
                    if fractional < rise {
                        let ratio = fractional / rise;
                        if pulse.low_voltage < pulse.high_voltage {
                            pulse.low_voltage + (pulse.high_voltage - pulse.low_voltage) * ratio
                        } else {
                            pulse.low_voltage - (pulse.low_voltage - pulse.high_voltage) * ratio
                        }
                    } else if fractional < high_voltage {
                        pulse.high_voltage
                    } else if fractional < fall {
                        let ratio = (fractional - high_voltage) / (fall - high_voltage);
                        if pulse.low_voltage < pulse.high_voltage {
                            pulse.high_voltage - (pulse.high_voltage - pulse.low_voltage) * ratio
                        } else {
                            pulse.high_voltage + (pulse.low_voltage - pulse.high_voltage) * ratio
                        }
                    } else {
                        pulse.low_voltage
                    }
                }
            }
        }
    }
}

// Vin N_in1 0 10
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct DCVoltageKind {
    pub value: f64
}

// Vin N_in1 0 sin(0 3 0.2k)
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct SinVoltageKind {
    pub bias: f64,
    pub amplitude: f64,
    pub frequence: f64
}

// Vin N_in1 0 PULSE 0 3 1m 1m 1m 8m 20m
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct PulseVoltageKind {
    pub low_voltage: f64,
    pub high_voltage: f64,
    pub delay: f64,
    pub rise_time: f64,
    pub fall_time: f64,
    pub pulse_width: f64,
    pub period: f64,
}

#[derive(Debug, PartialEq)]
pub struct Current {
    pub name: String,
    pub node1: String,
    pub node2: String,
    pub value: f64
}
